/**
 * Mock proxy server
 * @author Wangtd
 */
const fs = require('fs');
const http = require('http');
const httpProxy = require('http-proxy');

const config = require('../config.js');
const util = require('./util.js');

function ProxyServer(port, routes) {
    this.port = port;
    this.routes = routes;
    this.sockets = [];
    this._newInstance = function() {
        var _this = this;
        // mock proxy
        var proxy = httpProxy.createProxyServer({});
        // create proxy server
        _this.server = http.createServer(function(request, response) {
            var url = request.url;
            var module = request.headers['x-module'];
            if (module) {
                url = '/' + module + url;
            } else {
                var route = util.find(_this.routes, function(item) {
                    return item.enabled && url.indexOf(item.from) == 0;
                });
                if (route) {
                    url = url.replace(route.from, route.to);
                }
            }
            if (url == '/' || url.indexOf('/app/') == 0) {
                response.statusCode = 503;
                return response.end('Service Unavailable');
            }
            proxy.web(request, response, {
                target: 'http://localhost:' + config.port + url,
                ignorePath: true
            });
        });
    };
    this._newInstance();
};
ProxyServer.prototype.start = function() {
    var _this = this;
    // start proxy server
    _this.server.listen(_this.port, function(error) {
        if (error) {
            console.error(error);
        } else {
            console.log('Mock proxy server is running at http://localhost:%d/', _this.port);
        }
    }).on('connection', function(socket) {
        _this.sockets.push(socket);
        socket.once('close', function() {
            _this.sockets.splice(_this.sockets.indexOf(socket), 1);
        });
    });
};
ProxyServer.prototype.destroy = function() {
    if (this.server) {
        var _this = this;
        util.each(_this.sockets, function(socket) {
            socket.destroy();
        });
        _this.sockets = [];
        _this.server.close(function() {
            console.log('Mock proxy server is closed at http://localhost:%d/', _this.port);
        });
    }
};
ProxyServer.prototype.restart = function(routes, port) {
    this.routes = routes;
    if (port) {
        var _this = this;
        _this.port = port;
        _this.destroy();
        setTimeout(_this.start.bind(_this), 500);
    }
};

//mock proxy server
var proxyServers = {};

module.exports = {
    loadAllServers: function() {
        var cfgProxy = config.workDir + '/proxy.json';
        util.writeFileSync(cfgProxy, '[]');
        if (config.proxy.enabled) {
            // load all modules
            var files = fs.readdirSync(config.mockDir);
            var modules = [];
            for (var i in files) {
                var filename = files[i];
                var file = fs.statSync(config.mockDir + '/' + filename);
                if(file.isDirectory()) {
                    if (filename.indexOf('.') != 0) {// .git
                        modules.push(filename);
                    }
                }
            }
            // update proxy
            var newProxies = [];
            var proxies = JSON.parse(util.readFileSync(cfgProxy));
            util.each(modules, function(module) {
                var proxy = util.find(proxies, function(proxy) {
                    return proxy.module == module;
                });
                var offset = config.proxy.port.offset;
                if (proxy) {
                    // update offset
                    offset = Math.max(offset, proxy.port);
                } else {
                    // create module proxy
                    proxy = {
                        module: module,
                        port: ++offset,
                        routes: [{ from: '/', to: '/' + module + '/', enabled: true }]
                    };
                }
                config.proxy.port.offset = offset;
                newProxies.push(proxy);
            });
            util.writeFileSync(cfgProxy, JSON.stringify(newProxies, null, 2), true);
            // load proxy server
            util.each(newProxies, function(proxy) {
                var server = new ProxyServer(proxy.port, proxy.routes);
                proxyServers[proxy.module] = server;
                server.start();
            });
        } else {
            console.warn('Mock proxy servers are not available!');
        }
    },
    startServer: function(module, routes, port) {
        var server = proxyServers[module];
        if (server) {
            server.restart(routes, port);
        } else {
            server = new ProxyServer(port, routes);
            proxyServers[module] = server;
            server.start();
        }
    },
    destroyServer: function(module) {
        var server = proxyServers[module];
        if (server) {
            server.destroy();
            server = null;
        }
    }
};
